package org.benetech.beans;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jdom.Element;

/**
 * Filter implementation which accepts element names against one or more possible regular expressions. The callback
 * version of accept passes back the matcher that suceeeded. Note that if multiple elements are passed in to accept,
 * and only a subset passes, the callback will be called even though accept fails.
 *
 * @author Reuben Firmin
 */
public class NameOrIdMatchesFilter implements Filter<Element, Matcher> {

	private Pattern[] patterns;
	private FilterCallback callback;
	private boolean name;

	/**
	 * Construct with pattern to match element names against.
	 *
	 * @param patterns The pattern to match against
	 * @param name True to match against name, false to match against id
	 */
	public NameOrIdMatchesFilter(boolean name, final Pattern... patterns) {
		this(name, null, patterns);
	}

	/**
	 * Construct with pattern to match element names against, and a callback, forcing all calls to callback mode.
	 * @param callback The callback object to use
	 * @param patterns The pattern to match against
	 */
	public NameOrIdMatchesFilter(boolean name, final FilterCallback<Matcher> callback, final Pattern... patterns) {
		this.patterns = patterns;
		this.callback = callback;
		this.name = name;
	}



	/**
	 * {@inheritDoc}
	 */
	public boolean accept(final Element... elements) {
		return acceptWithCallback(callback, elements);
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean acceptWithCallback(final FilterCallback<Matcher> callback, final Element... elements) {
		if (elements.length == 0) {
			return false;
		}
		for (Element element : elements) {
			boolean found = false;
			for (Pattern pattern : patterns) {
				final Matcher matcher = pattern.matcher(name ? element.getName()
						: (element.getAttribute("id") == null ? "" : element.getAttribute("id").getValue()));
				if (matcher.matches()) {
					found = true;
					if (callback != null) {
						callback.callback(matcher);
					}
					break;
				}
			}
			if (!found) {
				return false;
			}
		}
		return true;
	}
}
